#include "gpio_capture.h"

static int capture_release(struct inode *inode, struct file *file);
static int capture_fasync(int fd, struct file *file, int on);
static ssize_t capture_read(struct file *file, char __user *buf, size_t len, loff_t *pos);

static void capture_work(struct work_struct *w);

static int capture_probe(struct platform_device *pdev);
static int capture_remove(struct platform_device *pdev);

//设备号
static dev_t capture_num;
//cdev对象
static struct cdev capture_cdev;
//class对象
static struct class *capture_class;
//操作函数
static struct file_operations capture_ops = {
	.owner = THIS_MODULE,
	.release = capture_release,
	.fasync = capture_fasync,
	.read = capture_read,
};
//capture资源
struct capture_handle capture_handle[CAPTURE_NUMBER];

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id capture_of_match[] = {
	{.compatible = "atk,capture"},
	{ /* Sentinel */ }
};
//平台驱动
struct platform_driver capture_drv = {
	.driver = {
		.name = "capture",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = capture_of_match,
	},
	.probe = capture_probe,
	.remove = capture_remove,
};

static int capture_release(struct inode *inode, struct file *file)
{
	capture_fasync(-1, file, 0);
	return 0;
}

static int capture_fasync(int fd, struct file *file, int on)
{
	uint32_t id;
	
	id = MINOR(file->f_inode->i_rdev);
	if(id > CAPTURE_NUMBER)
		return -EINVAL;

	return fasync_helper(fd, file, on, &capture_handle[id].fasync);
}

static ssize_t capture_read(struct file *file, char __user *buf, size_t len, loff_t *pos)
{
	uint32_t id;

	id = MINOR(file->f_inode->i_rdev);
	if((id > CAPTURE_NUMBER) || (len < sizeof(long long)))
		return -EINVAL;

	//以阻塞式打开，则加入等待队列并休眠
	if(!(file->f_flags & O_NONBLOCK))
	{
		capture_handle[id].update = 0;
		if(wait_event_interruptible(capture_handle[id].wait_queue, capture_handle[id].update))
			return -ERESTARTSYS;
	}

	if(copy_to_user(buf, &capture_handle[id].width, sizeof(long long)))
		return -EFAULT;

	return sizeof(long long);
}

static void capture_work(struct work_struct *w)
{
	struct capture_handle *capture = container_of(w, struct capture_handle, work);

	//读取输入状态
	if(gpio_get_value(capture->gpio) != capture->gpio_active)
	{
		//计算脉冲宽度
		capture->width = ktime_get_boottime_ns() - capture->begin_time;
		//发送信号通知相应进程
		kill_fasync(&capture->fasync, SIGIO, POLL_IN);
		//等待事件的进程
		capture->update = 1;
		wake_up_interruptible(&capture->wait_queue);
	}
	else
	{
		//记录脉冲第一个边沿的时间
		capture->begin_time = ktime_get_boottime_ns();
	}
}

static irqreturn_t capture_handler(int irq, void *dev)
{
	uint32_t id;

	id = (uint32_t)dev;

	//调度工作队列
	schedule_work(&capture_handle[id].work);

	//返回IRQ_HANDLED，表示中断被成功处理
	return IRQ_HANDLED;
}

//设备和驱动匹配成功执行
static int capture_probe(struct platform_device *pdev)
{
	int result;
	uint32_t id;
	uint32_t irq_flags;
	enum of_gpio_flags gpio_flags;
	struct device *device;

	printk("%s\r\n", __FUNCTION__);

	//获取设备ID号
	result = of_property_read_u32(pdev->dev.of_node, "id", &id);
	if(result != 0)
	{
		printk("get dev id failed\r\n");
		return result;
	}
	if(id > CAPTURE_NUMBER)
	{
		printk("dev id invalid\r\n");
		return -EINVAL;
	}
	if(capture_handle[id].use_flag) 
	{
		printk("dev id repetition\r\n");
		return -EINVAL;
	}
	pdev->id = id;

	//标记为已占用
	capture_handle[id].use_flag = 1;

	//初始化等待队列
	init_waitqueue_head(&capture_handle[id].wait_queue);

	//获取GPIO号
	capture_handle[id].gpio = of_get_named_gpio_flags(pdev->dev.of_node, "input_pin", 0, &gpio_flags);
	if(capture_handle[id].gpio < 0)
	{
		capture_handle[id].use_flag = 0;
		printk("get gpio failed\r\n");
		return capture_handle[id].gpio;
	}
	//提取GPIO活跃电平
	capture_handle[id].gpio_active = (gpio_flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
	//申请GPIO
	result = gpio_request(capture_handle[id].gpio, "capture");
	if(result != 0)
	{
		capture_handle[id].use_flag = 0;
		printk("request gpio failed\r\n");
		return result;
	}
	//设置GPIO为输入
	gpio_direction_input(capture_handle[id].gpio);

	//获取中断号
	capture_handle[id].irq = of_irq_get(pdev->dev.of_node, 0);
	if (capture_handle[id].irq <= 0)
	{
		gpio_free(capture_handle[id].gpio);
		capture_handle[id].use_flag = 0;
		printk("irq get failed");
		return capture_handle[id].irq;
	}
	//初始化工作队列
	INIT_WORK(&capture_handle[id].work, capture_work);
	//获取中断触发方式
	irq_flags = irq_get_trigger_type(capture_handle[id].irq);
	if(irq_flags == IRQF_TRIGGER_NONE)
		irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
	//注册中断
	result = request_irq(capture_handle[id].irq, capture_handler, irq_flags, "capture_irq", (void*)id);
	if(result != 0)
	{
		gpio_free(capture_handle[id].gpio);
		capture_handle[id].use_flag = 0;
		printk("request irq failed\r\n");
		return result;
	}

	//创建设备文件，将ID作为此设备的次设备号
	device = device_create(capture_class, NULL, capture_num+id, NULL, "capture-%d", id);
	if(IS_ERR(device))
	{
		free_irq(capture_handle[id].irq, (void*)id);
		gpio_free(capture_handle[id].gpio);
		capture_handle[id].use_flag = 0;
		printk("device create failed");
		return PTR_ERR(device);
	}

	capture_handle[id].begin_time = 0;
	capture_handle[id].width = 0;

	return 0;
}

//设备或驱动卸载时执行
static int capture_remove(struct platform_device *pdev)
{
	uint32_t id;

	printk("%s\r\n", __FUNCTION__);

	id = pdev->id;
	if(!capture_handle[id].use_flag)
	{
		printk("verification failed\r\n");
		return -EINVAL;
	}

	device_destroy(capture_class, capture_num+id);
	free_irq(capture_handle[id].irq, (void*)id);
	gpio_free(capture_handle[id].gpio);

	capture_handle[id].use_flag = 0;

	return 0;
}

static int __init capture_drv_init(void)
{
	int i;
	int err = 0;

	printk("%s\r\n", __FUNCTION__);

	for(i=0; i<CAPTURE_NUMBER; i++)
	{
		capture_handle[i].use_flag = 0;
		capture_handle[i].begin_time = 0;
	}

	//根据次设备号起始值动态注册字符设备号
	err = alloc_chrdev_region(&capture_num, 0, CAPTURE_NUMBER, "atk,capture");
	if(err != 0)
	{
		printk("alloc chrdev failed\r\n");
		return err;
	}
	printk("first device major %d, minor %d\r\n", MAJOR(capture_num), MINOR(capture_num));

	//初始化CDEV对象
	cdev_init(&capture_cdev, &capture_ops);
	//向系统添加CDEV对象
	err = cdev_add(&capture_cdev, capture_num, CAPTURE_NUMBER);
	if(err != 0)
	{
		unregister_chrdev_region(capture_num, CAPTURE_NUMBER);
		printk("add cdev failed\r\n");
		return err;
	}

	//创建class对象
	capture_class = class_create(THIS_MODULE, "capture,class");
	if(IS_ERR(capture_class))
	{
		cdev_del(&capture_cdev);
		unregister_chrdev_region(capture_num, CAPTURE_NUMBER);
		printk("class create failed");
		return PTR_ERR(capture_class);
	}

	//注册平台驱动
	err = platform_driver_register(&capture_drv);
	if(err != 0)
	{
		class_destroy(capture_class);
		cdev_del(&capture_cdev);
		unregister_chrdev_region(capture_num, CAPTURE_NUMBER);
		printk("add cdev failed\r\n");
		return err;
	}
	return err;
}

static void __exit capture_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&capture_drv);
	//销毁class对象
	class_destroy(capture_class);
	//从系统删除CDEV对象
	cdev_del(&capture_cdev);
	//注销字符设备号
	unregister_chrdev_region(capture_num, CAPTURE_NUMBER);
}

module_init(capture_drv_init);
module_exit(capture_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("capture_dev");
